home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Graphics / Ghostscript / source / sfxfd.c < prev    next >
C/C++ Source or Header  |  1997-03-28  |  9KB  |  314 lines

  1. /* Copyright (C) 1994, 1995, 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* sfxfd.c */
  20. /* File stream implementation using direct OS calls */
  21. /******
  22.  ****** NOTE: THIS FILE PROBABLY WILL NOT COMPILE ON NON-UNIX
  23.  ****** PLATFORMS, AND IT MAY REQUIRE EDITING ON SOME UNIX PLATFORMS.
  24.  ******/
  25. #include "stdio_.h"        /* includes std.h */
  26. #include "errno_.h"
  27. #include "memory_.h"
  28. /*
  29.  * It's likely that you will have to edit the next line on some Unix
  30.  * and most non-Unix platforms, since there is no standard (ANSI or
  31.  * otherwise) for where to find these definitions.
  32.  */
  33. /*
  34.  * unistd.h may declare unlink in a way that conflicts with stdio_.h if
  35.  * const has been disabled.
  36.  */
  37. #define unlink unlink_
  38. #include <unistd.h>        /* for read, write, fsync, lseek */
  39. #include "gdebug.h"
  40. #include "gpcheck.h"
  41. #include "stream.h"
  42. #include "strimpl.h"
  43.  
  44. /*
  45.  * This is an alternate implementation of file streams.  It still uses
  46.  * FILE * in the interface, but it uses direct OS calls for I/O.
  47.  * It also includes workarounds for the nasty habit of System V Unix
  48.  * of breaking out of read and write operations with EINTR, EAGAIN,
  49.  * and/or EWOULDBLOCK "errors".
  50.  *
  51.  * The interface should be identical to that of sfxstdio.c.  However, in
  52.  * order to allow both implementations to exist in the same executable, we
  53.  * optionally use different names for sread_file, swrite_file, and
  54.  * sappend_file (the public procedures).  See sfxboth.c.
  55.  */
  56. #ifndef KEEP_FILENO_API
  57. #  define sread_fileno sread_file
  58. #  define swrite_fileno swrite_file
  59. #  define sappend_fileno sappend_file
  60. #endif
  61.  
  62. /* Forward references for file stream procedures */
  63. private int
  64.   s_fileno_available(P2(stream *, long *)),
  65.   s_fileno_read_seek(P2(stream *, long)),
  66.   s_fileno_read_close(P1(stream *)),
  67.   s_fileno_read_process(P4(stream_state *, stream_cursor_read *,
  68.     stream_cursor_write *, bool));
  69. private int
  70.   s_fileno_write_seek(P2(stream *, long)),
  71.   s_fileno_write_flush(P1(stream *)),
  72.   s_fileno_write_close(P1(stream *)),
  73.   s_fileno_write_process(P4(stream_state *, stream_cursor_read *,
  74.     stream_cursor_write *, bool));
  75. private int
  76.   s_fileno_switch(P2(stream *, bool));
  77.  
  78. /* ------ File streams ------ */
  79.  
  80. /* Get the file descriptor number of a stream. */
  81. #define sfileno(s) fileno((s)->file)
  82.  
  83. /* Initialize a stream for reading an OS file. */
  84. void
  85. sread_fileno(register stream *s, FILE *file, byte *buf, uint len)
  86. {    static const stream_procs p =
  87.        {    s_fileno_available, s_fileno_read_seek, s_std_read_reset,
  88.         s_std_read_flush, s_fileno_read_close, s_fileno_read_process,
  89.         s_fileno_switch
  90.        };
  91.     /*
  92.      * There is no really portable way to test seekability,
  93.      * but this should work on most systems.
  94.      */
  95.     int fd = fileno(file);
  96.     long curpos = lseek(fd, 0L, SEEK_CUR);
  97.     bool seekable = (curpos != -1L && lseek(fd, curpos, SEEK_SET) != -1L);
  98.  
  99.     s_std_init(s, buf, len, &p,
  100.            (seekable ? s_mode_read + s_mode_seek : s_mode_read));
  101.     if_debug2('s', "[s]read file=0x%lx, fd=%d\n", (ulong)file,
  102.           fileno(file));
  103.     s->file = file;
  104.     s->file_modes = s->modes;
  105. }
  106. /* Procedures for reading from a file */
  107. private int
  108. s_fileno_available(register stream *s, long *pl)
  109. {    int fd = sfileno(s);
  110.     *pl = sbufavailable(s);
  111.     if ( sseekable(s) )
  112.        {    long pos, end;
  113.         pos = lseek(fd, 0L, SEEK_CUR);
  114.         if ( pos < 0 )
  115.           return ERRC;
  116.         end = lseek(fd, 0L, SEEK_END);
  117.         if ( lseek(fd, pos, SEEK_SET) < 0 || end < 0 )
  118.           return ERRC;
  119.         *pl += end - pos;
  120.         if ( *pl == 0 ) *pl = -1;    /* EOF */
  121.        }
  122.     else
  123.        {    if ( *pl == 0 ) *pl = -1;    /* EOF */
  124.        }
  125.     return 0;
  126. }
  127. private int
  128. s_fileno_read_seek(register stream *s, long pos)
  129. {    uint end = s->srlimit - s->cbuf + 1;
  130.     long offset = pos - s->position;
  131.     if ( offset >= 0 && offset <= end )
  132.        {    /* Staying within the same buffer */
  133.         s->srptr = s->cbuf + offset - 1;
  134.         return 0;
  135.        }
  136.     if ( lseek(sfileno(s), pos, SEEK_SET) < 0 )
  137.       return ERRC;
  138.     s->srptr = s->srlimit = s->cbuf - 1;
  139.     s->end_status = 0;
  140.     s->position = pos;
  141.     return 0;
  142. }
  143. private int
  144. s_fileno_read_close(stream *s)
  145. {    FILE *file = s->file;
  146.     if ( file != 0 )
  147.       {    s->file = 0;
  148.         return fclose(file);
  149.       }
  150.     return 0;
  151. }
  152.  
  153. /* Initialize a stream for writing an OS file. */
  154. void
  155. swrite_fileno(register stream *s, FILE *file, byte *buf, uint len)
  156. {    static const stream_procs p =
  157.        {    s_std_noavailable, s_fileno_write_seek, s_std_write_reset,
  158.         s_fileno_write_flush, s_fileno_write_close, s_fileno_write_process,
  159.         s_fileno_switch
  160.        };
  161.     s_std_init(s, buf, len, &p,
  162.            (file == stdout ? s_mode_write : s_mode_write + s_mode_seek));
  163.     if_debug2('s', "[s]write file=0x%lx, fd=%d\n", (ulong)file,
  164.           fileno(file));
  165.     s->file = file;
  166.     s->file_modes = s->modes;
  167. }
  168. /* Initialize for appending to an OS file. */
  169. void
  170. sappend_fileno(register stream *s, FILE *file, byte *buf, uint len)
  171. {    swrite_fileno(s, file, buf, len);
  172.     s->modes = s_mode_write + s_mode_append;    /* no seek */
  173.     s->file_modes = s->modes;
  174.     s->position = lseek(fileno(file), 0L, SEEK_END);
  175. }
  176. /* Procedures for writing on a file */
  177. private int
  178. s_fileno_write_seek(stream *s, long pos)
  179. {    /* We must flush the buffer to reposition. */
  180.     int code = sflush(s);
  181.     if ( code < 0 )
  182.       return code;
  183.     if ( lseek(sfileno(s), pos, SEEK_SET) < 0 )
  184.       return ERRC;
  185.     s->position = pos;
  186.     return 0;
  187. }
  188. private int
  189. s_fileno_write_flush(register stream *s)
  190. {    int result = s_process_write_buf(s, false);
  191.     discard(fsync(sfileno(s)));
  192.     return result;
  193. }
  194. private int
  195. s_fileno_write_close(register stream *s)
  196. {    s_process_write_buf(s, true);
  197.     return s_fileno_read_close(s);
  198. }
  199.  
  200. #define ss ((stream *)st)
  201.  
  202. /* Define the switch cases for System V interrupts. */
  203. #define case_again(errn) case errn: goto again;
  204. #ifdef EINTR
  205. #  define handle_EINTR() case_again(EINTR)
  206. #else
  207. #  define handle_EINTR() /* */
  208. #endif
  209. #if defined(EAGAIN) && (!defined(EINTR) || EAGAIN != EINTR)
  210. #  define handle_EAGAIN() case_again(EAGAIN)
  211. #else
  212. #  define handle_EAGAIN() /* */
  213. #endif
  214. #if defined(EWOULDBLOCK) && (!defined(EINTR) || EWOULDBLOCK != EINTR) && (!defined(EAGAIN) || EWOULDBLOCK != EAGAIN)
  215. #  define handle_EWOULDBLOCK() case_again(EWOULDBLOCK)
  216. #else
  217. #  define handle_EWOULDBLOCK() /* */
  218. #endif
  219. #define handle_SYSV_errno()\
  220.   handle_EINTR() handle_EAGAIN() handle_EWOULDBLOCK()
  221.  
  222. /* Process a buffer for a file reading stream. */
  223. /* This is the first stream in the pipeline, so pr is irrelevant. */
  224. private int
  225. s_fileno_read_process(stream_state *st, stream_cursor_read *ignore_pr,
  226.   stream_cursor_write *pw, bool last)
  227. {    int nread, status;
  228. again:    nread = read(sfileno(ss), pw->ptr + 1, (uint)(pw->limit - pw->ptr));
  229.     if ( nread > 0 )
  230.       {    pw->ptr += nread;
  231.         status = 0;
  232.       }
  233.     else if ( nread == 0 )
  234.       status = EOFC;
  235.     else switch ( errno )
  236.       {
  237.       handle_SYSV_errno() /* Handle System V interrupts */
  238.       default:
  239.         status = ERRC;
  240.       }
  241.     process_interrupts();
  242.     return status;
  243. }
  244.  
  245. /* Process a buffer for a file writing stream. */
  246. /* This is the last stream in the pipeline, so pw is irrelevant. */
  247. private int
  248. s_fileno_write_process(stream_state *st, stream_cursor_read *pr,
  249.   stream_cursor_write *ignore_pw, bool last)
  250. {    int nwrite, status;
  251.     uint count;
  252. again:    count = pr->limit - pr->ptr;
  253.     /* Some versions of the DEC C library on AXP architectures */
  254.     /* give an error on write if the count is zero! */
  255.     if ( count == 0 )
  256.       {    process_interrupts();
  257.         return 0;
  258.       }
  259.     nwrite = write(sfileno(ss), pr->ptr + 1, count);
  260.     if ( nwrite >= 0 )
  261.       {    pr->ptr += nwrite;
  262.         status = 0;
  263.       }
  264.     else switch ( errno )
  265.       {
  266.       handle_SYSV_errno() /* Handle System V interrupts */
  267.       default:
  268.         status = ERRC;
  269.       }
  270.     process_interrupts();
  271.     return status;
  272. }
  273.  
  274. #undef ss
  275.  
  276. /* Switch a file stream to reading or writing. */
  277. private int
  278. s_fileno_switch(stream *s, bool writing)
  279. {    uint modes = s->file_modes;
  280.     int fd = sfileno(s);
  281.     long pos;
  282.     if ( writing )
  283.       {    if ( !(s->file_modes & s_mode_write) )
  284.           return ERRC;
  285.         pos = stell(s);
  286.         if_debug2('s', "[s]switch 0x%lx to write at %ld\n",
  287.               (ulong)s, pos);
  288.         lseek(fd, pos, SEEK_SET);    /* pacify OS */
  289.         if ( modes & s_mode_append )
  290.           {    sappend_file(s, s->file, s->cbuf, s->cbsize);    /* sets position */
  291.           }
  292.         else
  293.           {    swrite_file(s, s->file, s->cbuf, s->cbsize);
  294.             s->position = pos;
  295.           }
  296.         s->modes = modes;
  297.       }
  298.     else
  299.       {    if ( !(s->file_modes & s_mode_read) )
  300.           return ERRC;
  301.         pos = stell(s);
  302.         if_debug2('s', "[s]switch 0x%lx to read at %ld\n",
  303.               (ulong)s, pos);
  304.         if ( sflush(s) < 0 )
  305.           return ERRC;
  306.         lseek(fd, 0L, SEEK_CUR);    /* pacify OS */
  307.         sread_file(s, s->file, s->cbuf, s->cbsize);
  308.         s->modes |= modes & s_mode_append;    /* don't lose append info */
  309.         s->position = pos;
  310.       }
  311.     s->file_modes = modes;
  312.     return 0;
  313. }
  314.